// INCLUDES
#include "../grrlib/GRRLIB/GRRLIB.h"
#include "../grrlib/GRRLIB/GRRLIB_addon.h"
#include "../grrlib/GRRLIB/GRRLIB_addon/GRRLIBfont.h"
#include "../grrlib/GRRLIB/GRRLIB_addon/GRRLIBbutton.h"

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <gccore.h>
#include <wiiuse/wpad.h>
#include <unistd.h>
#include <limits.h>
#include <malloc.h>
#include <string.h>
#include <math.h>
#include <ogc/lwp_watchdog.h>
#include <asndlib.h>
#include <gcmodplay.h> 

#include <ft2build.h>
#include FT_FREETYPE_H

#include "gfx/bmp_cursor.h"
#include "gfx/bmp_place_marked.h"
#include "gfx/bmp_place_unmarked.h"
#include "gfx/bmp_won.h"
#include "gfx/bmp_lost.h"
#include "gfx/bmp_cat_l.h"
#include "gfx/bmp_cat_r.h"
#include "gfx/bmp_cat_ul.h"
#include "gfx/bmp_cat_ur.h"
#include "gfx/bmp_cat_dl.h"
#include "gfx/bmp_cat_dr.h"
#include "gfx/bmp_background.h"
#include "gfx/bmp_button_green.h"
#include "gfx/bmp_button_cyan.h"
#include "gfx/bmp_button_red.h"

#include "fonts/Tempus_Sans_ITC_72_Bold.h"
#include "fonts/Narkisim_72_Bold.h"

#include "places.h"
#include "queue.h"

#include "effect1_pcm.h"
#include "track1_mod.h"

// DEFINES
#define BOOL    int
#define FALSE   0
#define TRUE    1

#define SCREEN_WIDTH	   640
#define HALF_SCREEN_WIDTH  320
#define SCREEN_HEIGHT	   480
#define HALF_SCREEN_HEIGHT 240

#define MIN_SIZE_X 5
#define MAX_SIZE_X 16
#define MIN_SIZE_Y 5
#define MAX_SIZE_Y 16

#define SIN_60 0.8660254

#define FIELD_HEIGHT 450.0

#define FONTSIZE_SMALL	24
#define FONTSIZE_MEDIUM	48
#define FONTSIZE_LARGE	72

#define TIME_WAIT		1000
#define TIME_MULTIPLY	0.95

// main variables
enum View {MAIN, CLASSIC, SPEEDCAT, OPTIONS, CREDITS};
enum Difficulty {EASY = 5, MEDIUM = 10, HARD = 20, INCREDIBLE = 30};

static MODPlay snd1;

Mtx GXmodelView2D;

// classic variables
int SIZE_X = 11;
int SIZE_Y = 11;

// classic and speedcat variables
float FIELD_WIDTH;
float HOR_ADD;
float VER_ADD;
float DIAMETER;
float RADIUS;
float RADIUS_SQUARE;
float DIAMETER_ORIG;
float RADIUS_ORIG;
float CAT_DIAMETER_ORIG;
float CAT_RADIUS_ORIG;
float LINE_DISTANCE;
float START_FIELD_X;
float START_FIELD_Y;
float SCALE;

// speedcat variables
int	round_nr;
u32	time_wait;
u32	time_start;

// Wiimote IR
ir_t ir;

enum View view;

BOOL done;
u32 pressed;
u32 held;

GRRLIB_texImg *tex_cursor = NULL;
GRRLIB_texImg *tex_place_marked = NULL;
GRRLIB_texImg *tex_place_unmarked = NULL;
GRRLIB_texImg *tex_won = NULL;
GRRLIB_texImg *tex_lost = NULL;
GRRLIB_texImg *tex_cat_l = NULL;
GRRLIB_texImg *tex_cat_r = NULL;
GRRLIB_texImg *tex_cat_ul = NULL;
GRRLIB_texImg *tex_cat_ur = NULL;
GRRLIB_texImg *tex_cat_dl = NULL;
GRRLIB_texImg *tex_cat_dr = NULL;
GRRLIB_texImg *tex_background = NULL;
GRRLIB_texImg *tex_button_red = NULL;
GRRLIB_texImg *tex_button_cyan = NULL;
GRRLIB_texImg *tex_button_green = NULL;

PLACE places[MAX_SIZE_X][MAX_SIZE_Y];

int catX, catY;
int prevCatX, prevCatY;

BOOL finished;
BOOL won;
enum Difficulty difficulty = 10;

static FT_Face ftFaceTempus;
static FT_Face ftFaceNarkisim;

// function prototypes
void restartSpeedCat();
void resetSpeedCatField();

int getXCoordForIndex(int x, int y) {
	return START_FIELD_X + x * DIAMETER + ((y & 1) == 0 ? 0 : RADIUS);
}

int getYCoordForIndex(int y) {
	return START_FIELD_Y + y * LINE_DISTANCE;
}

int getXIndexForCoord(int coordX, int y) {
	return round( (coordX - START_FIELD_X - ((y & 1) == 0 ? - 0 : RADIUS)) / DIAMETER );
}

int getYIndexForCoord(int coordY) {
	return round( (coordY - START_FIELD_Y) / LINE_DISTANCE );
}

PLACE* getNeighborForDirection(int direction, int x, int y) {
		PLACE* neighbor = NULL;
		if (y % 2 == 0) {
			switch (direction) {
			case 0:
				neighbor = &places[x - 1][y - 1];
				break;
			case 1:
				neighbor = &places[x][y - 1];
				break;
			case 2:
				neighbor = &places[x + 1][y];
				break;
			case 3:
				neighbor = &places[x][y + 1];
				break;
			case 4:
				neighbor = &places[x - 1][y + 1];
				break;
			case 5:
				neighbor = &places[x - 1][y];
				break;
			}
		}
		else {
			switch (direction) {
			case 0:
				neighbor = &places[x][y - 1];
				break;
			case 1:
				neighbor = &places[x + 1][y - 1];
				break;
			case 2:
				neighbor = &places[x + 1][y];
				break;
			case 3:
				neighbor = &places[x + 1][y + 1];
				break;
			case 4:
				neighbor = &places[x][y + 1];
				break;
			case 5:
				neighbor = &places[x - 1][y];
				break;
			}			
		}
		return neighbor;
}

void getNeighbors(int x, int y, PLACE* neighbors[]) {
	int i;
	for (i = 0; i < 6; i++) {
		neighbors[i] = getNeighborForDirection(i, x, y);
	}
}

PLACE* getPlaceForCoord(int coordX, int coordY) {
	int y = getYIndexForCoord(coordY);
	int x = getXIndexForCoord(coordX, y);
	
	if ((x >= 0) && (x < SIZE_X) && (y >= 0) && (y < SIZE_Y)) {
		float dist = (places[x][y].posX - coordX)*(places[x][y].posX - coordX)
				+ (places[x][y].posY - coordY)*(places[x][y].posY - coordY);
		if (dist < RADIUS_SQUARE)
			return &places[x][y];
	}
		
	return NULL;
}

void drawBackground() {
	GRRLIB_DrawImg(0, 0, tex_background, 0, 1, 1, 0xFFFFFFFF);
}

void drawPlaces() {
	int x, y;
	for (x = 0; x < SIZE_X; x++) {
		for (y = 0; y < SIZE_Y; y++) {
	
			GRRLIB_DrawImg(places[x][y].posX - RADIUS_ORIG, places[x][y].posY - RADIUS_ORIG,
					places[x][y].marked ? tex_place_marked : tex_place_unmarked,
					0, SCALE, SCALE, 0xFFFFFFFF);
			
			/* // debugging only
			int d = places[x][y].distance;
			if (d == INT_MAX)
				d = -1;
			
			GRRLIB_Printf(places[x][y].posX - RADIUS, places[x][y].posY - RADIUS,
					tex_GRRLIBfont, 0x00000000FF, 1, "%d", d);
			*/

			usleep(10);
		}
	}
}

void drawCat() {

	int direction = 5;
	PLACE* catPlace = &places[catX][catY];
	int i = 0;
	for (i = 0; i < 6; i++)	{
		if (getNeighborForDirection(i, prevCatX, prevCatY) == catPlace) {
			direction = i;
			break;
		}
	}
	GRRLIB_texImg *tex_cat;
	switch (direction) {
		case 0:
			tex_cat = tex_cat_ul;
			break;
		case 1:
			tex_cat = tex_cat_ur;
			break;
		case 2:
			tex_cat = tex_cat_r;
			break;
		case 3:
			tex_cat = tex_cat_dr;
			break;
		case 4:
			tex_cat = tex_cat_dl;
			break;
		case 5:
			tex_cat = tex_cat_l;
			break;
		default:
			tex_cat = tex_cat_l;
			break;
	}

	int coordX = getXCoordForIndex(catX, catY);
	int coordY = getYCoordForIndex(catY);
	
	GRRLIB_DrawImg(coordX - CAT_RADIUS_ORIG, coordY - CAT_RADIUS_ORIG,
			tex_cat, 0, SCALE, SCALE, 0xFFFFFFFF);
}

void drawClassicEnd() {
	GRRLIB_texImg *text;
	text = won ? tex_won : tex_lost;
	GRRLIB_DrawImg((SCREEN_WIDTH - text->w) / 2, (SCREEN_HEIGHT - text->h) / 2, text, 0, 1, 1, 0xFFFFFFFF);
}

void drawSpeedCatEnd() {
	int resdown = 0, resheld = 0;
	
	int wpadx=ir.x;
	int wpady=ir.y;
	
	GRRLIB_texImg *text;
	text = won ? tex_won : tex_lost;
	GRRLIB_DrawImg((SCREEN_WIDTH - text->w) >> 1, 100, text, 0, 1, 1, 0xFFFFFFFF);
	
	// Init text layer
	GRRLIB_initTexture();

	if (!won) {
		// rounds won
		char endText[100];
		sprintf(endText, "Rounds won: %d", round_nr-1); 
		int textWidth = GRRLIB_TextWidth(endText, ftFaceNarkisim, 64);
		GRRLIB_Printf2((SCREEN_WIDTH - textWidth) >> 1, 250, endText, ftFaceNarkisim, 64, 0x000000);
		
		// Try Again-Button
		GRRLIB_addon_ImageButton(1, 93, 350, tex_button_red, ftFaceNarkisim, 36,
			0xBBBBBB, 0xFFFFFF, wpadx, wpady, pressed, held,
			WPAD_BUTTON_A, &resdown, &resheld, "Try Again");
		
		// Main-Button
		GRRLIB_addon_ImageButton(2, 367, 350, tex_button_red, ftFaceNarkisim, 36,
			0xBBBBBB, 0xFFFFFF, wpadx, wpady, pressed, held,
			WPAD_BUTTON_A, &resdown, &resheld, "Main");
			
		// button pressed?
		if (resdown == 1) {
			restartSpeedCat();
			resetSpeedCatField();
			view = SPEEDCAT;
		}
		else if (resdown == 2) {
			view = MAIN;
		}
	}
	else {
		// Next Round-Button
		GRRLIB_addon_ImageButton(1, 230, 350, tex_button_red, ftFaceNarkisim, 36,
			0xBBBBBB, 0xFFFFFF, wpadx, wpady, pressed, held,
			WPAD_BUTTON_A, &resdown, &resheld, "Next Round");
		
		// button pressed?
		if (resdown == 1) {
			resetSpeedCatField();
		}
	}
	
	// Draw text layer
	GRRLIB_DrawImg(0, 0, GRRLIB_GetTexture(), 0, 1.0, 1.0, 0xFFFFFFFF);
}

BOOL markPlace(int coordX, int coordY) {
	PLACE* place = getPlaceForCoord(coordX, coordY);
	if (place == NULL) {
		return FALSE;
	}
	if ((place->x == catX) && (place->y == catY)) {
		return FALSE;
	}
	if (place->marked) {
		return FALSE;
	}
	place->marked = TRUE;
	return TRUE;
}

int calcShortestPathes(PlaceList* shortestPathes) {
	
	int shortestPathesSize = 0;

	int x, y;
	for (y = 0; y < SIZE_Y; y++) {
		for (x = 0; x < SIZE_X; x++) {
			PLACE* place = &places[x][y];
			place->visited = FALSE;
			place->distance = INT_MAX;
			place->reachedFrom = NULL;
		}
	}
	
	PLACE* place = &places[catX][catY];
	place->distance = 0;
	place->visited = TRUE;

	PlaceList* queue;
	queue = place_list_create();
	int queueSize = 0;
	
	place_list_append_constant_time (queue, place);
	queueSize++;

	int shortestEscape = INT_MAX;
	
	// dijkstra
	while (queueSize > 0) {

		PLACE* actPlace;
		actPlace = place_list_pop(queue);
		queueSize--;
		
		PLACE* neighbors[6];
		getNeighbors(actPlace->x, actPlace->y, neighbors);
		
		int i;
		for (i = 0; i < 6; i++) {
			PLACE* neighbor;
			neighbor = neighbors[i];
			
			if (neighbor->marked)
				continue;
			
			int newDistance = actPlace->distance + 1;
			if (newDistance < neighbor->distance) {
				neighbor->distance = newDistance;
				neighbor->reachedFrom = actPlace;
			}
			if (!neighbor->visited && !neighbor->escape) {
				place_list_append_constant_time(queue, neighbor);
				queueSize++;
				neighbor->visited = TRUE;
			}
			
			if (neighbor->escape) {
				if (neighbor->distance < shortestEscape) {
					shortestEscape = neighbor->distance;
					place_list_clear(shortestPathes);
					place_list_append_constant_time(shortestPathes, neighbor);
					shortestPathesSize = 1;
				}
				else if (neighbor->distance == shortestEscape) {
					place_list_append_constant_time(shortestPathes, neighbor);
					shortestPathesSize++;
				}
			}
		}
	}
	
	place_list_clear(queue);
	free(queue);
	
	return shortestPathesSize;
}

BOOL moveCat() {

	prevCatX = catX;
	prevCatY = catY;

	PlaceList* shortestPathes;
	shortestPathes = place_list_create();
	int shortestPathesSize = 0;
	
	shortestPathesSize = calcShortestPathes(shortestPathes);
	
	if (place_list_is_empty(shortestPathes)) {
		// no escape reachable
		PLACE* neighbors[6];
		getNeighbors(catX, catY, neighbors);
		
		PlaceList* reachableNeighbors;
		reachableNeighbors = place_list_create();
		
		int size = 0;
		int i = 0;
		for (i = 0; i < 6; i++) {
			PLACE* neighbor = neighbors[i];
			if (!neighbor->marked) {
				place_list_append_constant_time(reachableNeighbors, neighbor);
				size++;
			}
		}
	
		if (size == 0) {
			won = true;
			return true;
		}
		
		srand(time(NULL));
		int dir = rand() % size;
		PLACE* rn = place_list_element_at(reachableNeighbors, dir);
		
		catX = rn->x;
		catY = rn->y;
		
		place_list_clear(reachableNeighbors);
		free(reachableNeighbors);
	}
	else {
		// random from shortestPathes
		srand(time(NULL));
		int rp = rand() % shortestPathesSize;
		PLACE* prevPlace = place_list_element_at(shortestPathes, rp);
		while (prevPlace->reachedFrom != &places[catX][catY]) {
			prevPlace = prevPlace->reachedFrom;
		}
	
		catX = prevPlace->x;
		catY = prevPlace->y;
	}
		
	if (places[catX][catY].escape) {
		won = FALSE;
		return TRUE;
	}
	
	//place_list_clear(queue);
	//free(queue);
	place_list_clear(shortestPathes);
	free(shortestPathes);

	return FALSE;
}

void restartClassic() {

    // set variables
	RADIUS = FIELD_HEIGHT / (2 * (SIZE_Y - 1) * SIN_60 + 2);
	DIAMETER = 2 * RADIUS;
	RADIUS_SQUARE = RADIUS * RADIUS;
	
	LINE_DISTANCE = SIN_60 * 2 * RADIUS;
	
	DIAMETER_ORIG = tex_place_unmarked->w;
	RADIUS_ORIG = DIAMETER_ORIG / 2;
	
	CAT_DIAMETER_ORIG = tex_cat_l->w;
	CAT_RADIUS_ORIG = CAT_DIAMETER_ORIG / 2;
	
	SCALE = DIAMETER / DIAMETER_ORIG;
	
	FIELD_WIDTH = SIZE_X * DIAMETER + RADIUS;

	HOR_ADD = (SCREEN_WIDTH - FIELD_WIDTH) / 2;
	VER_ADD = (SCREEN_HEIGHT - FIELD_HEIGHT) / 2;

	START_FIELD_X = RADIUS + HOR_ADD;
	START_FIELD_Y = RADIUS + VER_ADD;
	
	// create field
	int x, y;
	srand(time(NULL));
	for (x = 0; x < SIZE_X; x++) {
		for (y = 0; y < SIZE_Y; y++) {
			places[x][y].x = x;
			places[x][y].y = y;
			places[x][y].posX = getXCoordForIndex(x, y);
			places[x][y].posY = getYCoordForIndex(y);
			if ((x == 0) || (x == SIZE_X - 1) || (y == 0) || (y == SIZE_Y - 1)) {
				places[x][y].escape = TRUE;
			}
			else {
				places[x][y].escape = FALSE;
			}
			places[x][y].marked = rand() % difficulty == 0;	
		}
	}
	
	// reset cat
	catX = SIZE_X >> 1;
	catY = SIZE_Y >> 1;
	
	prevCatX = catX;
	prevCatY = catY;
	
	// place with cat must not be marked
	places[catX][catY].marked = FALSE;
	
	// set variables
	finished = FALSE;
	won = FALSE;
}

void restartSpeedCat() {

    // set variables, SIZE_X and SIZE_Y = 11
	RADIUS = FIELD_HEIGHT / (2 * (11 - 1) * SIN_60 + 2);
	DIAMETER = 2 * RADIUS;
	RADIUS_SQUARE = RADIUS * RADIUS;
	
	LINE_DISTANCE = SIN_60 * 2 * RADIUS;
	
	DIAMETER_ORIG = tex_place_unmarked->w;
	RADIUS_ORIG = DIAMETER_ORIG / 2;
	
	CAT_DIAMETER_ORIG = tex_cat_l->w;
	CAT_RADIUS_ORIG = CAT_DIAMETER_ORIG / 2;
	
	SCALE = DIAMETER / DIAMETER_ORIG;
	
	FIELD_WIDTH = 11 * DIAMETER + RADIUS;

	HOR_ADD = (SCREEN_WIDTH - FIELD_WIDTH) / 2;
	VER_ADD = (SCREEN_HEIGHT - FIELD_HEIGHT) / 2;

	START_FIELD_X = RADIUS + HOR_ADD;
	START_FIELD_Y = RADIUS + VER_ADD;
	
	// set speedcat variables
	round_nr = 0;
	time_wait = TIME_WAIT;
}

void resetSpeedCatField() {
	// create field
	int x, y;
	srand(time(NULL));
	for (x = 0; x < 11; x++) {
		for (y = 0; y < 11; y++) {
			places[x][y].x = x;
			places[x][y].y = y;
			places[x][y].posX = getXCoordForIndex(x, y);
			places[x][y].posY = getYCoordForIndex(y);
			if ((x == 0) || (x == 11 - 1) || (y == 0) || (y == 11 - 1)) {
				places[x][y].escape = TRUE;
			}
			else {
				places[x][y].escape = FALSE;
			}
			places[x][y].marked = rand() % MEDIUM == 0;	
		}
	}
	
	// reset cat
	catX = 11 >> 1;
	catY = 11 >> 1;
	
	prevCatX = catX;
	prevCatY = catY;
	
	// place with cat must not be marked
	places[catX][catY].marked = FALSE;
	
	// set variables
	finished = FALSE;
	won = FALSE;
	
	// set speedcat variables
	round_nr++;
	time_wait *= TIME_MULTIPLY;
	time_start = ticks_to_millisecs(gettime());
}

void renderMain() {
	int resdown = 0, resheld = 0;
	
	int wpadx=ir.x;
	int wpady=ir.y;
	
	// Init text layer
	GRRLIB_initTexture();  

	// Main
	GRRLIB_Printf2(260, 20, "Main", ftFaceNarkisim, 72, 0x333333);
	
	// Classic-Button
	GRRLIB_addon_ImageButton(1, 93, 150, tex_button_red, ftFaceNarkisim, 36,
		0xBBBBBB, 0xFFFFFF, wpadx, wpady, pressed, held,
		WPAD_BUTTON_A, &resdown, &resheld, "Classic");

	// SppedCat-Button
	GRRLIB_addon_ImageButton(2, 367, 150, tex_button_red, ftFaceNarkisim, 36,
		0xBBBBBB, 0xFFFFFF, wpadx, wpady, pressed, held,
		WPAD_BUTTON_A, &resdown, &resheld, "SpeedCat");

	// Credits-Button
	GRRLIB_addon_ImageButton(3, 230, 250, tex_button_red, ftFaceNarkisim, 36,
		0xBBBBBB, 0xFFFFFF, wpadx, wpady, pressed, held,
		WPAD_BUTTON_A, &resdown, &resheld, "Credits");
	
	// Quit-Button
	GRRLIB_addon_ImageButton(4, 230, 350, tex_button_red, ftFaceNarkisim, 36,
		0xBBBBBB, 0xFFFFFF, wpadx, wpady, pressed, held,
		WPAD_BUTTON_A, &resdown, &resheld, "Quit");
	
	// Draw text layer
	GRRLIB_DrawImg(0, 0, GRRLIB_GetTexture(), 0, 1.0, 1.0, 0xFFFFFFFF);
	
	// button pressed?
	if (resdown == 1) {
		restartClassic();
		view = CLASSIC;
	}
	else if (resdown == 2) {
		restartSpeedCat();
		resetSpeedCatField();
		view = SPEEDCAT;
	}
	else if (resdown == 3) {
		view = CREDITS;
	}
	else if (resdown == 4) {
		done = TRUE;
	}
}

void renderClassic() {
	// draw places
	drawPlaces();
	
	// draw cat
	drawCat();
	
	// draw won or lost text
	if (finished) {
		drawClassicEnd();
	}
	
	if (pressed & WPAD_BUTTON_HOME) {
		view = MAIN;
	}
	else if (pressed & WPAD_BUTTON_A) {
		if (!finished) {
			if (markPlace(ir.x, ir.y)) {
				finished = moveCat();
			}
		}
	}
	else if (pressed & WPAD_BUTTON_PLUS) {
		restartClassic();
	}
	else if (pressed & WPAD_BUTTON_MINUS) {
		view = OPTIONS;
	}
}

void renderSpeedCat() {
	// draw places
	drawPlaces();
	
	// draw cat
	drawCat();
	
	if (!finished) {
		// calc time
		u32 time_act = ticks_to_millisecs(gettime());
		if (time_act - time_start > time_wait) {
			// time for next move
			finished = moveCat();
			time_start = time_act;
		}
	}
	else {
		// draw won or lost text
		drawSpeedCatEnd();
	}
	
	if (pressed & WPAD_BUTTON_HOME) {
		view = MAIN;
	}
	else if (pressed & WPAD_BUTTON_A) {
		if (!finished) {
			// block the place
			markPlace(ir.x, ir.y);
			
			// find out wether cat is blocked
			PLACE* neighbors[6];
			getNeighbors(catX, catY, neighbors);
			BOOL catBlocked = TRUE;
			int i;
			for (i = 0; i < 6; i++) {
				if (!neighbors[i]->marked) {
					catBlocked = FALSE;
				}
			}
			if (catBlocked) {
				won = TRUE;
				finished = TRUE;
			}
		}
	}
}

void renderOptions() {
	int resdown = 0, resheld = 0;
	
	int wpadx=ir.x;
	int wpady=ir.y;

	// Init text layer
	GRRLIB_initTexture();   
	
	// Options
	GRRLIB_Printf2(210, 20, "Options", ftFaceNarkisim, 72, 0x333333);
	
	// Difficulty
	GRRLIB_Printf2(120, 153, "Difficulty: ", ftFaceNarkisim, 36, 0x333333);
	
	// Difficulty-Button
	char* text_diff = difficulty == EASY ? "Easy" : difficulty == MEDIUM ? 
		"Medium" : difficulty == HARD ? "Hard" : "Incredible";
	GRRLIB_addon_ImageButton(1, 340, 150, tex_button_green, ftFaceNarkisim, 36,
		0xBBBBBB, 0xFFFFFF, wpadx, wpady, pressed, held,
		WPAD_BUTTON_A, &resdown, &resheld, text_diff);
	
	// Size
	GRRLIB_Printf2(120, 253, "Size: ", ftFaceNarkisim, 36, 0x333333);
	
	// Size-Button
	char text_size[2];
	sprintf(text_size, "%d", SIZE_X);
	GRRLIB_addon_ImageButton(2, 340, 250, tex_button_green, ftFaceNarkisim, 36,
		0xBBBBBB, 0xFFFFFF, wpadx, wpady, pressed, held,
		WPAD_BUTTON_A, &resdown, &resheld, text_size);

	// Back-Button
	GRRLIB_addon_ImageButton(3, 230, 380, tex_button_red, ftFaceNarkisim, 36,
		0xBBBBBB, 0xFFFFFF, wpadx, wpady, pressed, held,
		WPAD_BUTTON_A, &resdown, &resheld, "Back");

	// Draw text layer
	GRRLIB_DrawImg(0, 0, GRRLIB_GetTexture(), 0, 1.0, 1.0, 0xFFFFFFFF);

	// button pressed?
	if (resdown == 1) {
		difficulty = (difficulty == EASY ? MEDIUM : difficulty == MEDIUM ? 
		HARD : difficulty == HARD ? INCREDIBLE : EASY);
	}
	else if (resdown == 2) {
		int new_size = (SIZE_X + 1);
		if (new_size > 15)
			new_size = 5;
		SIZE_X = new_size;
		SIZE_Y = new_size;
	}
	else if (resdown == 3) {
		restartClassic();
		view = CLASSIC;
		return;
	}

	// key on wiimote pressed?
	if (pressed & WPAD_BUTTON_MINUS) {
		restartClassic();
		view = CLASSIC;
	}

}

void renderCredits() {
	int resdown = 0, resheld = 0;
	
	int wpadx=ir.x;
	int wpady=ir.y;
	
	// Init text layer
	GRRLIB_initTexture();
	
	// The team
	GRRLIB_Printf2(220, 20, "Credits", ftFaceNarkisim, 72, 0x333333);
	
	GRRLIB_Printf2(130, 133, "TippiX", ftFaceNarkisim, 36, 0x333333);
	GRRLIB_Printf2(360, 133, "Project Lead,", ftFaceNarkisim, 36, 0x333333);
	GRRLIB_Printf2(360, 173, "Coding", ftFaceNarkisim, 36, 0x333333);
	
	GRRLIB_Printf2(130, 233, "Gamer-D", ftFaceNarkisim, 36, 0x333333);
	GRRLIB_Printf2(360, 233, "Graphics,", ftFaceNarkisim, 36, 0x333333);
	GRRLIB_Printf2(360, 273, "Nice Ideas", ftFaceNarkisim, 36, 0x333333);
	
	// Back-Button
	GRRLIB_addon_ImageButton(1, 230, 380, tex_button_red, ftFaceNarkisim, 36,
		0xBBBBBB, 0xFFFFFF, wpadx, wpady, pressed, held,
		WPAD_BUTTON_A, &resdown, &resheld, "Back");
	
	// Draw text layer
	GRRLIB_DrawImg(0, 0, GRRLIB_GetTexture(), 0, 1.0, 1.0, 0xFFFFFFFF);
	
		// button pressed?
	if (resdown == 1) {
		view = MAIN;
	}
}

void init() {
    // button initialization
    WPAD_Init();
	WPAD_SetVRes(0, SCREEN_WIDTH, SCREEN_HEIGHT);
	WPAD_SetDataFormat(WPAD_CHAN_0, WPAD_FMT_BTNS_ACC_IR);
 
    // Load the image file to a texture structure
    tex_cursor = GRRLIB_LoadTexture(bmp_cursor);
	
    tex_place_marked = GRRLIB_LoadTexture(bmp_place_marked);
	tex_place_unmarked = GRRLIB_LoadTexture(bmp_place_unmarked);
    tex_won = GRRLIB_LoadTexture(bmp_won);
	tex_lost = GRRLIB_LoadTexture(bmp_lost);
	tex_cat_l = GRRLIB_LoadTexture(bmp_cat_l);
	tex_cat_r = GRRLIB_LoadTexture(bmp_cat_r);
	tex_cat_ul = GRRLIB_LoadTexture(bmp_cat_ul);
	tex_cat_ur = GRRLIB_LoadTexture(bmp_cat_ur);
	tex_cat_dl = GRRLIB_LoadTexture(bmp_cat_dl);
	tex_cat_dr = GRRLIB_LoadTexture(bmp_cat_dr);
	tex_background = GRRLIB_LoadTexture(bmp_background);
	tex_button_red = GRRLIB_LoadTexture(bmp_button_red);
	tex_button_cyan = GRRLIB_LoadTexture(bmp_button_cyan);
	tex_button_green = GRRLIB_LoadTexture(bmp_button_green);
	
	GRRLIB_Init();
	GRRLIB_addon_Init();
	GRRLIB_InitFreetype();
	// init fonts
	GRRLIB_InitFreetypeFont(Tempus_Sans_ITC_72_Bold, Tempus_Sans_ITC_72_Bold_size, &ftFaceTempus);
	GRRLIB_InitFreetypeFont(Narkisim_72_Bold, Narkisim_72_Bold_size, &ftFaceNarkisim);
	
	ASND_Init();
	MODPlay_Init(&snd1);
	SND_Pause(0);
	
	//SND_SetVoice(0, VOICE_MONO_8BIT, 8000, 0, (u8 *) effect1_pcm, effect1_pcm_size, 255, 255, NULL);
	
	MODPlay_SetMOD(&snd1, track1_mod);
	MODPlay_SetVolume(&snd1, 10, 10);
	MODPlay_Start(&snd1);	
	
	
	//view = MAIN;
	//view = CLASSIC;
	
	//restartSpeedCat();
	//resetSpeedCatField();
	//view = SPEEDCAT;
	
	//view = OPTIONS;
	view = CREDITS;
}

void cleanup() {
	ASND_End();
    GRRLIB_Exit(); 
    GRRLIB_FreeTexture(tex_cursor);
    GRRLIB_FreeTexture(tex_place_marked);
    GRRLIB_FreeTexture(tex_place_unmarked);
    GRRLIB_FreeTexture(tex_won);
    GRRLIB_FreeTexture(tex_lost);
	GRRLIB_FreeTexture(tex_cat_l);
	GRRLIB_FreeTexture(tex_cat_r);
	GRRLIB_FreeTexture(tex_cat_ul);
	GRRLIB_FreeTexture(tex_cat_ur);
	GRRLIB_FreeTexture(tex_cat_dl);
	GRRLIB_FreeTexture(tex_cat_dr);
	GRRLIB_FreeTexture(tex_background);
	GRRLIB_FreeTexture(tex_button_red);
	GRRLIB_FreeTexture(tex_button_green);
	GRRLIB_FreeTexture(tex_button_cyan);
}
 
int main(int argc, char** argv) {

	// to stop the while loop
	done = FALSE;
 
	// start init() function
	init();
 
	// this is the endless while loop until done = true
	while (!done) {
		drawBackground();

		// scans if a button was pressed
        WPAD_ScanPads();
		pressed = WPAD_ButtonsDown(0);
		held = WPAD_ButtonsHeld(0);
		
		// IR Movement
		WPAD_IR(0, &ir);
	
		if (view == MAIN) {
			renderMain();
		}
		else if (view == CLASSIC) {
			renderClassic();
		}
		else if (view == SPEEDCAT) {
			renderSpeedCat();
		}
		else if (view == OPTIONS) {
			renderOptions();
		}
		else if (view == CREDITS) {
			renderCredits();
		}
	
		// draw Cursor
        GRRLIB_DrawImg(ir.x - 48, ir.y - 48, tex_cursor, ir.angle, 1, 1, 0xFFFFFFFF);

		// finally render frame
		GRRLIB_Render();
	}
 
	// start cleanup() function
	cleanup();
 
    return 0;
}


